 package uk.co.mmscomputing.device.twain;
 
 import java.io.PrintStream;
 import uk.co.mmscomputing.concurrent.Semaphore;
 import uk.co.mmscomputing.concurrent.TimeUnit;
 import uk.co.mmscomputing.device.scanner.ScannerDevice;
 import uk.co.mmscomputing.device.scanner.ScannerIOException;
 
 public class TwainSource extends TwainIdentity
   implements TwainConstants, ScannerDevice
 {
   private boolean busy;
   private int state;
   private long hWnd;
   private int showUI = 1;
   private int modalUI = 0;
 
   private int iff = 2;
   private TwainITransferFactory transferFactory;
   private boolean userCancelled;
   private Semaphore tw20Semaphore = null;
   private boolean tw20HaveImage = false;
 
   TwainSource(TwainSourceManager paramTwainSourceManager, long paramLong, boolean paramBoolean) {
     super(paramTwainSourceManager);
     this.hWnd = paramLong;
     this.busy = paramBoolean;
     this.state = 3;
 
     this.userCancelled = false;
     this.transferFactory = new TwainDefaultTransferFactory();
   }
   byte[] getIdentity() {
     return this.identity;
   }
   public boolean isBusy() { return this.busy; } 
   void setBusy(boolean paramBoolean) { this.busy = paramBoolean; jtwain.signalStateChange(this); } 
   public int getState() { return this.state; } 
   void setState(int paramInt) { this.state = paramInt; jtwain.signalStateChange(this); } 
   public void setCancel(boolean paramBoolean) {
     this.userCancelled = paramBoolean; } 
   public boolean getCancel() { return this.userCancelled; }
 
   void checkState(int paramInt) throws TwainIOException
   {
     if (this.state == paramInt) return;
     throw new TwainIOException(getClass().getName() + ".checkState:\n\tSource not in state " + paramInt + " but in state " + this.state + ".");
   }
 
   int getConditionCode() throws TwainIOException {
     byte[] arrayOfByte = new byte[4];
     int i = jtwain.callSource(this.identity, 1, 8, 1, arrayOfByte);
     if (i != 0) {
       throw new TwainResultException("Cannot retrieve twain source's status.", i);
     }
     return jtwain.getINT16(arrayOfByte, 0);
   }
 
   private void checkrc(int paramInt) throws TwainIOException {
     switch (paramInt) { case 0:
       return;
     case 1:
       throw TwainFailureException.create(getConditionCode());
     case 2:
       throw new TwainResultException.CheckStatus();
     case 3:
       throw new TwainResultException.Cancel();
     case 4:
       return;
     case 5:
       throw new TwainResultException.NotDSEvent();
     case 6:
       throw new TwainResultException.TransferDone();
     case 7:
       throw new TwainResultException.EndOfList();
     case 8:
       throw new TwainResultException.InfoNotSupported();
     case 9:
       throw new TwainResultException.DataNotAvailable();
     }
     System.err.println(getClass().getName() + ".checkrc\n\trc=" + paramInt);
     throw new TwainResultException("Failed to call source.", paramInt);
   }
 
   public void call(int paramInt1, int paramInt2, int paramInt3, byte[] paramArrayOfByte) throws TwainIOException
   {
     checkrc(jtwain.callSource(this.identity, paramInt1, paramInt2, paramInt3, paramArrayOfByte));
   }
 
   private void setCallbackProcedure()
     throws TwainIOException
   {
     byte[] arrayOfByte = new byte[jtwain.getPtrSize() == 4 ? 10 : 14];
     int i = jtwain.setPtr(arrayOfByte, 0, jtwain.getCallBackMethod());
     jtwain.setINT32(arrayOfByte, i, 0);
     i += 4; jtwain.setINT16(arrayOfByte, i, 0);
     call(1, 16, 2306, arrayOfByte);
   }
 
   void open() throws TwainIOException {
     super.open();
     if (isTwain20Source())
       try {
         setCallbackProcedure();
       } catch (Exception localException) {
         maskTwain20Source();
         System.out.println("3\b" + getClass().getName() + ".open:\n\tCannot set twain 2.0 callback method.");
         System.err.println(getClass().getName() + ".open:\n\tCannot set twain 2.0 callback method.");
       }
   }
 
   public TwainCapability[] getCapabilities() throws TwainIOException
   {
     return TwainCapability.getCapabilities(this);
   }
 
   public TwainCapability getCapability(int paramInt) throws TwainIOException {
     return new TwainCapability(this, paramInt);
   }
 
   public TwainCapability getCapability(int paramInt1, int paramInt2) throws TwainIOException {
     return new TwainCapability(this, paramInt1, paramInt2);
   }
 
   public TwainITransferFactory getTransferFactory() {
     return this.transferFactory;
   }
 
   public void setTransferFactory(TwainITransferFactory paramTwainITransferFactory) {
     if (paramTwainITransferFactory == null) {
       throw new IllegalArgumentException(getClass().getName() + ".setTransferFactory\n\tTwain transfer factory cannot be null.");
     }
     this.transferFactory = paramTwainITransferFactory;
   }
   public void setShowUI(boolean paramBoolean) {
     this.showUI = (paramBoolean ? 1 : 0); } 
   public boolean isModalUI() { return this.modalUI == 1; }
 
   public void setCapability(int paramInt, boolean paramBoolean) throws ScannerIOException {
     TwainCapability localTwainCapability = getCapability(paramInt, 2);
     if (localTwainCapability.booleanValue() != paramBoolean) {
       localTwainCapability.setCurrentValue(paramBoolean);
       if (getCapability(paramInt).booleanValue() != paramBoolean)
         throw new ScannerIOException(getClass().getName() + ".setCapability:\n\tCannot set capability " + TwainCapability.getCapName(paramInt) + " to " + paramBoolean);
     }
   }
 
   public void setCapability(int paramInt1, int paramInt2) throws ScannerIOException
   {
     TwainCapability localTwainCapability = getCapability(paramInt1, 2);
     if (localTwainCapability.intValue() != paramInt2) {
       localTwainCapability.setCurrentValue(paramInt2);
       if (getCapability(paramInt1).intValue() != paramInt2)
         throw new ScannerIOException(getClass().getName() + ".setCapability:\n\tCannot set capability " + TwainCapability.getCapName(paramInt1) + " to " + paramInt2);
     }
   }
 
   public void setCapability(int paramInt, double paramDouble) throws ScannerIOException
   {
     TwainCapability localTwainCapability = getCapability(paramInt, 2);
     if (localTwainCapability.doubleValue() != paramDouble) {
       localTwainCapability.setCurrentValue(paramDouble);
       if (getCapability(paramInt).doubleValue() != paramDouble)
         throw new ScannerIOException(getClass().getName() + ".setCapability:\n\tCannot set capability " + TwainCapability.getCapName(paramInt) + " to " + paramDouble);
     }
   }
 
   public boolean isUIControllable()
   {
     try
     {
       return getCapability(4110).booleanValue();
     } catch (Exception localException) {
       jtwain.signalException(getClass().getName() + ".isUIControllable:\n\t" + localException); } return false;
   }
 
   public boolean isDeviceOnline()
   {
     try {
       return getCapability(4111).booleanValue();
     } catch (Exception localException) {
       jtwain.signalException(getClass().getName() + ".isOnline:\n\t" + localException); } return true;
   }
 
   public void setShowUserInterface(boolean paramBoolean) throws ScannerIOException
   {
     setShowUI(paramBoolean);
   }
 
   public void setShowProgressBar(boolean paramBoolean) throws ScannerIOException {
     setCapability(4107, paramBoolean);
   }
 
   public void setResolution(double paramDouble) throws ScannerIOException {
     setCapability(258, 0);
     setCapability(4376, paramDouble);
     setCapability(4377, paramDouble);
   }
 
   public void setRegionOfInterest(int paramInt1, int paramInt2, int paramInt3, int paramInt4) throws ScannerIOException {
     if ((paramInt1 == -1) && (paramInt2 == -1) && (paramInt3 == -1) && (paramInt4 == -1)) {
       new TwainImageLayout(this).reset();
     } else {
       setCapability(258, 5);
       TwainImageLayout localTwainImageLayout = new TwainImageLayout(this);
       localTwainImageLayout.get();
       localTwainImageLayout.setLeft(paramInt1); localTwainImageLayout.setTop(paramInt2);
       localTwainImageLayout.setRight(paramInt1 + paramInt3); localTwainImageLayout.setBottom(paramInt2 + paramInt4);
       localTwainImageLayout.set();
     }
   }
 
   public void setRegionOfInterest(double paramDouble1, double paramDouble2, double paramDouble3, double paramDouble4) throws ScannerIOException {
     if ((paramDouble1 == -1.0D) && (paramDouble2 == -1.0D) && (paramDouble3 == -1.0D) && (paramDouble4 == -1.0D)) {
       new TwainImageLayout(this).reset();
     } else {
       setCapability(258, 1);
       TwainImageLayout localTwainImageLayout = new TwainImageLayout(this);
       localTwainImageLayout.get();
       localTwainImageLayout.setLeft(paramDouble1 / 10.0D); localTwainImageLayout.setTop(paramDouble2 / 10.0D);
       localTwainImageLayout.setRight((paramDouble1 + paramDouble3) / 10.0D); localTwainImageLayout.setBottom((paramDouble2 + paramDouble4) / 10.0D);
       localTwainImageLayout.set();
     }
   }
 
   public void select(String paramString) throws ScannerIOException
   {
     checkState(3);
     TwainSourceManager localTwainSourceManager = jtwain.getSourceManager();
     try {
       TwainIdentity localTwainIdentity = new TwainIdentity(localTwainSourceManager);
       localTwainIdentity.getFirst();
       while (true) {
         if (localTwainIdentity.getProductName().equals(paramString)) {
           System.arraycopy(localTwainIdentity.identity, 0, this.identity, 0, this.identity.length); break;
         }
         localTwainIdentity.getNext();
       }
     } catch (TwainResultException.EndOfList localEndOfList) {
       throw new TwainIOException(getClass().getName() + ".select(String name)\n\tCannot find twain data source: '" + paramString + "'");
     }
   }
 
   void enable()
     throws TwainIOException
   {
     checkState(4);
     jtwain.negotiateCapabilities(this);
     if (getState() < 4) return;
 
     int i = new TwainCapability.XferMech(this).intValue();
     if ((i != 0) && 
       (i == 1)) {
       try {
         this.iff = getCapability(4364).intValue();
       } catch (Exception localException) {
         this.iff = 2;
       }
     }
     if (isTwain20Source()) {
       this.tw20Semaphore = new Semaphore(0, true);
       this.tw20HaveImage = false;
     }
     byte[] arrayOfByte = null;
     try {
       arrayOfByte = new byte[jtwain.getPtrSize() == 4 ? 8 : 12];
       jtwain.setINT16(arrayOfByte, 0, this.showUI);
       jtwain.setINT16(arrayOfByte, 2, this.modalUI);
       jtwain.setPtr(arrayOfByte, 4, this.hWnd);
 
       call(1, 9, 1282, arrayOfByte);
       this.modalUI = jtwain.getINT16(arrayOfByte, 2);
       setState(5);
     }
     catch (TwainResultException.CheckStatus localCheckStatus) {
       setState(5);
       this.showUI = ((this.showUI ^ 0xFFFFFFFF) & 0x1);
     } catch (TwainResultException.Cancel localCancel) {
       disable();
       close();
     }
     if (isTwain20Source())
       try {
         this.tw20Semaphore.tryAcquire(60000L, TimeUnit.MILLISECONDS);
         this.tw20Semaphore.release();
 
         if (this.tw20HaveImage == true) {
           transferImage();
         } else {
           System.out.println("9\b" + getClass().getName() + ".enable:\n\tscan timed out. Close data source.");
           System.err.println(getClass().getName() + ".enable:\n\tscan timed out Close data source.");
         }
       } catch (TwainIOException localTwainIOException) {
         System.out.println("9\b" + getClass().getName() + ".enable:\n\t" + localTwainIOException);
         System.err.println(getClass().getName() + ".enable:\n\t" + localTwainIOException);
       } catch (InterruptedException localInterruptedException) {
         System.out.println("9\b" + getClass().getName() + ".enable:\n\tscan interrupted");
         System.err.println(getClass().getName() + ".enable:\n\tscan interrupted");
       }
   }
 
   private void transfer(TwainITransfer paramTwainITransfer) throws TwainIOException
   {
     try {
       byte[] arrayOfByte = new byte[6];
       do {
         setState(6);
         jtwain.setINT16(arrayOfByte, 0, -1);
         try {
           paramTwainITransfer.setCancel(this.userCancelled);
           paramTwainITransfer.initiate();
         } catch (TwainResultException.TransferDone localTransferDone) {
           setState(7);
           paramTwainITransfer.finish();
           call(1, 5, 1793, arrayOfByte);
           if (jtwain.getINT16(arrayOfByte, 0) == 0)
             setState(5);
         }
         catch (TwainUserCancelException localTwainUserCancelException) {
           call(1, 5, 7, arrayOfByte);
           setState(5);
         } catch (TwainResultException.Cancel localCancel) {
           paramTwainITransfer.cancel();
 
           call(1, 5, 1793, arrayOfByte);
           if (jtwain.getINT16(arrayOfByte, 0) > 0) {
             call(1, 5, 7, arrayOfByte);
           }
           setState(5);
         } catch (TwainFailureException localTwainFailureException) {
           jtwain.signalException(getClass().getName() + ".transfer:\n\t" + localTwainFailureException);
 
           call(1, 5, 1793, arrayOfByte);
           if (jtwain.getINT16(arrayOfByte, 0) > 0) {
             call(1, 5, 7, arrayOfByte);
           }
           setState(5);
         } finally {
           paramTwainITransfer.cleanup();
         }
       }
       while (jtwain.getINT16(arrayOfByte, 0) != 0);
     } finally {
       if ((this.userCancelled) || (this.showUI == 0)) {
         this.userCancelled = false;
         disable();
         close();
       }
     }
   }
 
   void transferImage() throws TwainIOException {
     switch (getXferMech()) { case 0:
       transfer(this.transferFactory.createNativeTransfer(this)); break;
     case 1:
       transfer(this.transferFactory.createFileTransfer(this)); break;
     case 2:
       transfer(this.transferFactory.createMemoryTransfer(this)); break;
     default:
       System.out.println(getClass().getName() + ".transferImage:\n\tDo not support this transfer mode: " + getXferMech());
       System.err.println(getClass().getName() + ".transferImage:\n\tDo not support this transfer mode: " + getXferMech()); }
   }
 
   void disable()
     throws TwainIOException
   {
     if (this.state < 5) return;
 
     byte[] arrayOfByte = new byte[jtwain.getPtrSize() == 4 ? 8 : 12];
     jtwain.setINT16(arrayOfByte, 0, -1);
     jtwain.setINT16(arrayOfByte, 2, 0);
     jtwain.setPtr(arrayOfByte, 4, this.hWnd);
 
     call(1, 9, 1281, arrayOfByte);
     setState(4);
   }
 
   void close() throws TwainIOException {
     if (this.state != 4) return;
     call(1, 3, 1026, this.identity);
     this.busy = false;
     setState(3);
   }
 
   int callback(int paramInt1, int paramInt2, int paramInt3, long paramLong) throws TwainIOException {
     switch (paramInt3) {
     case 257:
       this.tw20HaveImage = true;
       this.tw20Semaphore.release();
       break;
     case 258:
     case 259:
       System.err.println("MSG_CLOSEDSOK,MSG_CLOSEDSREQ in callback routine");
       this.tw20HaveImage = false;
       this.tw20Semaphore.release();
       break;
     case 0:
     case 260:
       break;
     default:
       System.err.println("9\b" + getClass().getName() + ".callback:\n\tUnknown message in Twain 2.0 callback routine");
       return 1;
     }
     return 0;
   }
 
   int handleGetMessage(long paramLong) throws TwainIOException {
     if (this.state < 5) return 5; try
     {
       byte[] arrayOfByte = new byte[jtwain.getPtrSize() == 4 ? 6 : 10];
       int i = jtwain.setPtr(arrayOfByte, 0, paramLong);
       jtwain.setINT16(arrayOfByte, i, 0);
       call(1, 2, 1537, arrayOfByte);
       int j = jtwain.getINT16(arrayOfByte, i);
       switch (j) {
       case 257:
         transferImage();
         break;
       case 258:
       case 259:
         disable();
         close();
         break;
       case 0:
       case 260:
       }
 
       return 4; } catch (TwainResultException.NotDSEvent localNotDSEvent) {
     }
     return 5;
   }
 
   public int getXferMech() throws TwainIOException
   {
     return new TwainCapability.XferMech(this).intValue();
   }
 
   public void setXferMech(int paramInt) {
     try {
       switch (paramInt) { case 0:
       case 1:
       case 2:
         break;
       default:
         paramInt = 0;
       }
 
       TwainCapability localTwainCapability = getCapability(259, 2);
       if (localTwainCapability.intValue() != paramInt) {
         localTwainCapability.setCurrentValue(paramInt);
         if (getCapability(259).intValue() != paramInt)
           jtwain.signalException(getClass().getName() + ".setXferMech:\n\tCannot change transfer mechanism to mode=" + paramInt);
       }
     }
     catch (TwainIOException localTwainIOException) {
       jtwain.signalException(getClass().getName() + ".setXferMech:\n\t" + localTwainIOException);
     }
   }
 
   int getImageFileFormat() { return this.iff; }
 
   public void setImageFileFormat(int paramInt)
   {
     try {
       switch (paramInt) { case 0:
       case 2:
       case 4:
       case 6:
       case 7:
         break;
       case 1:
       case 3:
       case 5:
       default:
         paramInt = 2;
       }
 
       TwainCapability localTwainCapability = getCapability(4364, 2);
       if (localTwainCapability.intValue() != paramInt) {
         localTwainCapability.setCurrentValue(paramInt);
         if (getCapability(4364).intValue() != paramInt)
           jtwain.signalException(getClass().getName() + ".setImageFileFormat:\n\tCannot change file format to format=" + paramInt);
       }
     }
     catch (Exception localException) {
       jtwain.signalException(getClass().getName() + ".setImageFileFormat:\n\t" + localException);
     }
   }
 }

